package cn.com.cfae.iras.doc.analyze.parse.extractor;

import cn.com.cfae.iras.doc.analyze.parse.GsonUtil;
import cn.com.cfae.iras.doc.analyze.parse.RegexUtil;
import cn.com.cfae.iras.doc.analyze.parse.SimilarAnalyser;
import cn.com.cfae.iras.doc.analyze.parse.TableUtil;
import cn.com.cfae.iras.doc.analyze.parse.kv.KVItem;
import cn.com.cfae.iras.doc.analyze.parse.kv.KVTableParser;
import cn.com.cfae.iras.doc.analyze.parse.kv.KVText;
import cn.com.cfae.iras.doc.analyze.parse.kv.TextLayout;
import cn.com.cfae.iras.doc.analyze.parse.model.*;
import cn.com.cfae.iras.doc.analyze.parse.model.table.BaseTable;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 公募M表抽取逻辑
 */
public class MTableExtractor extends TableExtractor {
    private static final Logger logger = LoggerFactory.getLogger(MTableExtractor.class);

    public MTableExtractor() {
    }

    public ExtractBizModel getExtractBizModel(String modelName) {
        return getChapterModel().getExtractBizModelMap().get(modelName);
    }

    public ChapterModel getChapterModel() {
        return getDocumentModel().getChapterModel(getTableId());
    }

    public List<PageModel> getPageModelList() {
        return getChapterModel().getPageModelList();
    }

    public PageModel getAssignPageModel(int pageNumber) {
        PageModel targetPageModel = null;
        for (PageModel pageModel : getPageModelList()) {
            if (pageNumber == pageModel.getPageNumber()) {
                targetPageModel = pageModel;
                break;
            }
        }
        return targetPageModel;
    }

    private BaseTable baseTable;

    public BaseTable getBaseTable() {
        return baseTable;
    }

    public void setBaseTable(BaseTable baseTable) {
        this.baseTable = baseTable;
    }

    /**
     * 子类需实现该方法
     */
    public void extract() {
    }

    public String getTableId() {
        return tableId;
    }

    public void setTableId(String tableId) {
        this.tableId = tableId;
        Map<String, ExtractBizModel> extractBizModelMap = getBaseTable().getExtractBizModelMap(tableId);
        this.documentModel.getChapterModel(tableId).setExtractBizModelMap(extractBizModelMap);
    }

    private void printSynonyms(Map<String, ExtractBizModel> extractBizModelMap) {
        File file = new File("./iras-dict.txt");
        for (Iterator<String> it = extractBizModelMap.keySet().iterator(); it.hasNext(); ) {
            String key = it.next();
            ExtractBizModel extractBizModel = extractBizModelMap.get(key);
            List<ExtractItem> extractItemList = extractBizModel.getExtractItemList();
            for (ExtractItem extractItem : extractItemList) {
                try {
                    FileUtils.writeLines(file, Arrays.asList(extractItem.getSynonyms()), true);
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    }

    private String tableId;

    private RegexUtil regexUtil = new RegexUtil();

    private GsonUtil gsonUtil = GsonUtil.getInstance();

    private SimilarAnalyser similarAnalyser = SimilarAnalyser.getInstance();

    protected SimilarAnalyser getSimilarAnalyser() {
        return similarAnalyser;
    }


    public DocumentModel getDocumentModel() {
        return documentModel;
    }

    public void setDocumentModel(DocumentModel documentModel) {
        this.documentModel = documentModel;
    }

    private DocumentModel documentModel;

    public MTableExtractor(DocumentModel documentModel) {
        this.documentModel = documentModel;
    }

    protected String obj2Json(Object object) {
        return gsonUtil.toJson(object);
    }


    protected void setKV(ExtractItem extractItem, JsonElement k, JsonElement v, JsonElement tableData) {
        if (k.getAsJsonObject().get("text").getAsString().isEmpty()) {
            return;
        }
        KVText key = new KVText();
        key.setText(k.getAsJsonObject().get("text").getAsString());
        TextLayout keyTextLaytou = null;
        keyTextLaytou = createKVTextLayout(k.getAsJsonObject());
//        keyTextLaytou.setTop(k.getAsJsonObject().get("top").getAsDouble());
//        keyTextLaytou.setLeft(k.getAsJsonObject().get("left").getAsDouble());
//        keyTextLaytou.setWidth(k.getAsJsonObject().get("width").getAsDouble());
//        keyTextLaytou.setHeight(k.getAsJsonObject().get("height").getAsDouble());
        keyTextLaytou.setText(key.getText());
        key.add(keyTextLaytou);
        extractItem.setKey(key);

        KVText value = new KVText();
        value.setText(v.getAsJsonObject().get("text").getAsString());
        TextLayout valueTextLaytou = null;
        valueTextLaytou = findTextArea2(v, tableData);
        if (valueTextLaytou == null) {
            valueTextLaytou = createKVTextLayout(k.getAsJsonObject());
        }
//        valueTextLaytou.setTop(v.getAsJsonObject().get("top").getAsDouble());
//        valueTextLaytou.setLeft(v.getAsJsonObject().get("left").getAsDouble());
//        valueTextLaytou.setWidth(v.getAsJsonObject().get("width").getAsDouble());
//        valueTextLaytou.setHeight(v.getAsJsonObject().get("height").getAsDouble());
        valueTextLaytou.setText(value.getText());
        value.add(valueTextLaytou);
        extractItem.setValue(value);
    }


    protected void setKV(ExtractItem extractItem, JsonElement k, JsonElement v) {
        if (k.getAsJsonObject().get("text").getAsString().isEmpty()) {
            return;
        }
        KVText key = new KVText();
        key.setText(k.getAsJsonObject().get("text").getAsString());
        TextLayout keyTextLaytou = null;
        keyTextLaytou = createKVTextLayout(k.getAsJsonObject());
//        keyTextLaytou.setTop(k.getAsJsonObject().get("top").getAsDouble());
//        keyTextLaytou.setLeft(k.getAsJsonObject().get("left").getAsDouble());
//        keyTextLaytou.setWidth(k.getAsJsonObject().get("width").getAsDouble());
//        keyTextLaytou.setHeight(k.getAsJsonObject().get("height").getAsDouble());
        keyTextLaytou.setText(key.getText());
        key.add(keyTextLaytou);
        extractItem.setKey(key);


        KVText value = new KVText();
        value.setText(v.getAsJsonObject().get("text").getAsString());
        TextLayout valueTextLaytou = null;
        valueTextLaytou = createKVTextLayout(k.getAsJsonObject());
//        valueTextLaytou.setTop(v.getAsJsonObject().get("top").getAsDouble());
//        valueTextLaytou.setLeft(v.getAsJsonObject().get("left").getAsDouble());
//        valueTextLaytou.setWidth(v.getAsJsonObject().get("width").getAsDouble());
//        valueTextLaytou.setHeight(v.getAsJsonObject().get("height").getAsDouble());
        valueTextLaytou.setText(value.getText());
        value.add(keyTextLaytou);
        extractItem.setValue(value);
    }

    protected void setKV(JsonArray dataArray, ExtractItem extractItem) {
        if (extractItem.getKey() != null) {
            return;
        }
        JsonElement keyData = findValidTableCell(dataArray);
        JsonElement valueData = keyData;
        String combineLine = combineTextJsonArray(dataArray);
        String splitChar = findFXTK_Format_Split_Char(combineLine);
        KVText key = new KVText();
        key.add(createKVTextLayout(keyData.getAsJsonObject()));
        extractItem.setKey(key);
        KVText value = new KVText();
        value.add(createKVTextLayout(keyData.getAsJsonObject()));
        extractItem.setValue(value);
        String[] splits = combineLine.split(splitChar, 2);
        if (splits.length > 1) {
            key.setText(splits[0]);
            key.getTextLayout().setText(replaceSpecialChar(key.getText()));
            value.setText(splits[splits.length - 1]);
            value.getTextLayout().setText(value.getText());
        }
    }

    protected void setFXR_Table_KV(List<JsonObject> validJsonObjectList, int offset, ExtractItem extractItem, PageModel pageModel) {
        setFXTK_Table_KV(validJsonObjectList, offset, extractItem, pageModel);
    }


    protected List<PageModel> getFragmentPageModeList(int startPage, int endPage) {
        List<PageModel> fragmentPageModelList = new ArrayList<>();
        for (int i = startPage; i <= endPage; i++) {
            fragmentPageModelList.add(getAssignPageModel(i));
        }
        return fragmentPageModelList;
    }

    protected void setZYYW_Table_KV(JsonElement keyData, JsonElement valueData, ExtractItem extractItem, PageModel pageModel) {
        if (extractItem.getKey() != null) {
            return;
        }
        KVText key = new KVText();
        TextLayout keyTextLayout = null;
        if (pageModel == null) {
            keyTextLayout = new TextLayout();
            keyTextLayout.setWidth(keyData.getAsJsonObject().get("width").getAsDouble());
            keyTextLayout.setHeight(keyData.getAsJsonObject().get("height").getAsDouble());
            keyTextLayout.setTop(keyData.getAsJsonObject().get("top").getAsDouble());
            keyTextLayout.setLeft(keyData.getAsJsonObject().get("left").getAsDouble());
            key.setText(keyData.getAsJsonObject().get("text").getAsString());
            keyTextLayout.setText(replaceSpecialChar(key.getText()));
            key.add(keyTextLayout);
        } else {
            key.add(findTextArea(keyData, pageModel.getJsonTextData()));
            key.setText(keyData.getAsJsonObject().get("text").getAsString());
            key.getTextLayout().setText(key.getText());
        }
        extractItem.setKey(key);
        KVText value = new KVText();
        TextLayout valueTextLayout = new TextLayout();
        valueTextLayout.setWidth(key.getTextLayout().getWidth());
        valueTextLayout.setHeight(key.getTextLayout().getHeight());
        valueTextLayout.setTop(key.getTextLayout().getTop());
        valueTextLayout.setLeft(key.getTextLayout().getLeft());
        value.setText(valueData.getAsJsonObject().get("text").getAsString());
        valueTextLayout.setText(value.getText());
        value.add(valueTextLayout);
        extractItem.setValue(value);
    }

    protected void setFXTK_Table_KV(List<JsonObject> validJsonObjectList, int offset, ExtractItem extractItem, PageModel pageModel) {
        JsonElement keyData = validJsonObjectList.get(offset);
        JsonElement valueData = validJsonObjectList.get(validJsonObjectList.size() - 1);
        KVText key = new KVText();
        TextLayout keyTextLayout = null;
        if (pageModel == null) {
            keyTextLayout = createKVTextLayout(pageModel, keyData.getAsJsonObject());
            key.setText(keyData.getAsJsonObject().get("text").getAsString());
            keyTextLayout.setText(replaceSpecialChar(key.getText()));
            key.add(keyTextLayout);
        } else {
            keyTextLayout = findTextArea(validJsonObjectList.get(offset), pageModel.getJsonTextData());
            if (keyTextLayout == null) {
                keyTextLayout = createKVTextLayout(pageModel, keyData.getAsJsonObject());
            }
            key.setText(keyData.getAsJsonObject().get("text").getAsString());
            key.add(keyTextLayout);
            key.getTextLayout().setText(key.getText());
        }
        extractItem.setKey(key);
        KVText value = new KVText();
        TextLayout valueTextLayout = createKVTextLayout(pageModel, valueData.getAsJsonObject());
        value.setText(valueData.getAsJsonObject().get("text").getAsString());
        valueTextLayout.setText(value.getText());
        value.add(valueTextLayout);
        extractItem.setValue(value);
    }

    protected void setFXTK_Table_KV(List<JsonObject> validJsonObjectList, int offset, ExtractItem extractItem) {
        setFXTK_Table_KV(validJsonObjectList, offset, extractItem, null);
    }


    protected void setFXTK_KV(JsonArray dataArray, ExtractItem extractItem) {
        if (extractItem.getKey() != null) {
            return;
        }
        JsonElement keyData = dataArray.get(0);
        JsonElement valueData = keyData;//dataArray.get(1);
        String combineLine = combineTextJsonArray(dataArray);
        String splitChar = findFXTK_Format_Split_Char(combineLine);
        KVText key = new KVText();
        TextLayout keyTextLayout = new TextLayout();
        keyTextLayout.setWidth(keyData.getAsJsonObject().get("width").getAsDouble());
        keyTextLayout.setHeight(keyData.getAsJsonObject().get("height").getAsDouble());
        keyTextLayout.setTop(keyData.getAsJsonObject().get("top").getAsDouble());
        keyTextLayout.setLeft(keyData.getAsJsonObject().get("left").getAsDouble());
        key.add(keyTextLayout);
        extractItem.setKey(key);
        ///////////////////////////////////////
        KVText value = new KVText();
        TextLayout valueTextLayout = new TextLayout();
        valueTextLayout.setWidth(valueData.getAsJsonObject().get("width").getAsDouble());
        valueTextLayout.setHeight(valueData.getAsJsonObject().get("height").getAsDouble());
        valueTextLayout.setTop(valueData.getAsJsonObject().get("top").getAsDouble());
        valueTextLayout.setLeft(valueData.getAsJsonObject().get("left").getAsDouble());
        value.add(valueTextLayout);
        extractItem.setValue(value);
        String[] splits = combineLine.split(splitChar, 2);
        if (splits.length > 1) {
            key.setText(splits[0]);
            keyTextLayout.setText(key.getText());
            value.setText(splits[1]);
            valueTextLayout.setText(replaceSpecialChar(value.getText()));
        } else {
            //TODO key正好在中间，文本在上下位置，后边再处理
            if (isNotEmpty(splitChar)) {
                key.setText(combineLine);
                keyTextLayout.setText(replaceSpecialChar(key.getText()));
            }
        }
    }


    protected void setFXR_KV(JsonArray dataArray, ExtractItem extractItem) {
        if (extractItem.getKey() != null) {
            return;
        }
        JsonElement keyData = dataArray.get(0);
        JsonElement valueData = keyData;//dataArray.get(1);
        String combineLine = combineTextJsonArray(dataArray);
        String splitChar = findFXTK_Format_Split_Char(combineLine);
        KVText key = new KVText();
        TextLayout keyTextLayout = new TextLayout();
        keyTextLayout.setWidth(keyData.getAsJsonObject().get("width").getAsDouble());
        keyTextLayout.setHeight(keyData.getAsJsonObject().get("height").getAsDouble());
        keyTextLayout.setTop(keyData.getAsJsonObject().get("top").getAsDouble());
        keyTextLayout.setLeft(keyData.getAsJsonObject().get("left").getAsDouble());
        key.add(keyTextLayout);
        extractItem.setKey(key);
        ///////////////////////////////////////
        KVText value = new KVText();
        TextLayout valueTextLayout = new TextLayout();
        valueTextLayout.setWidth(valueData.getAsJsonObject().get("width").getAsDouble());
        valueTextLayout.setHeight(valueData.getAsJsonObject().get("height").getAsDouble());
        valueTextLayout.setTop(valueData.getAsJsonObject().get("top").getAsDouble());
        valueTextLayout.setLeft(valueData.getAsJsonObject().get("left").getAsDouble());
        value.add(valueTextLayout);
        extractItem.setValue(value);
        String[] splits = combineLine.split(splitChar, 2);
        if (splits.length > 1) {
            key.setText(splits[0]);
            keyTextLayout.setText(key.getText());
            value.setText(splits[1]);
            valueTextLayout.setText(value.getText());
        } else {
            //TODO key正好在中间，文本在上下位置，后边再处理
            if (isNotEmpty(splitChar)) {
                key.setText(combineLine);
                keyTextLayout.setText(key.getText());
            }
        }
    }

    protected String combineTextJsonArray(JsonArray jsonArray) {
        StringBuilder stringBuilder = new StringBuilder();
        JsonObject item = null;
        JsonObject previousItem = null;
        for (int i = 0; i < jsonArray.size(); i++) {
            item = jsonArray.get(i).getAsJsonObject();
            String text = item.get("text").getAsString().trim();
            if (StringUtils.isEmpty(text)) {
                continue;
            }
            if (i > 0) {
                previousItem = jsonArray.get(i - 1).getAsJsonObject();
                if (previousItem != null) {
                    double previousLeft = previousItem.get("left").getAsDouble();
                    if (previousLeft == 0) {
                        stringBuilder.append(text);
                    } else {
                        double itemLeft = item.get("left").getAsDouble();
                        if ((itemLeft - previousLeft) > 20) {
                            stringBuilder.append(" ");
                        }
                        stringBuilder.append(replaceSpaces(text));
                    }
                } else {
                    stringBuilder.append(text);
                }
            } else {
                stringBuilder.append(text);
            }
        }
        return stringBuilder.toString();
    }


    protected void setSY_TableKV(int offset, List<JsonObject> validJsonObjectList, ExtractItem extractItem, PageModel pageModel) {
        JsonElement keyData = validJsonObjectList.get(offset);
        JsonElement valueData = validJsonObjectList.get(validJsonObjectList.size() - 1);
        if (extractItem.getKey() != null) {
            return;
        }
        KVText key = new KVText();
        TextLayout keyTextLayout = null;
        if (pageModel == null) {
            keyTextLayout = createKVTextLayout(pageModel, keyData.getAsJsonObject());
            key.setText(replaceSpecialChar(keyData.getAsJsonObject().get("text").getAsString()));
            key.add(keyTextLayout);
        } else {
            keyTextLayout = findTextArea(validJsonObjectList.get(offset), pageModel.getJsonTextData());
            if (keyTextLayout == null) {
                keyTextLayout = createKVTextLayout(pageModel, keyData.getAsJsonObject());
            }
            key.add(keyTextLayout);
        }

        int i = 0;
        String text = key.getTextLayout().getText();
        if (text.contains("\r")) {
            StringTokenizer tokenizer = new StringTokenizer(text, "\r");
            while (tokenizer.hasMoreElements()) {
                if (i == 0) {
                    key.getTextLayout().setText((String) tokenizer.nextElement());
                    break;
                }
            }
        }
        extractItem.setKey(key);
        KVText value = new KVText();
        TextLayout valueTextLayout = createKVTextLayout(pageModel, valueData.getAsJsonObject());
        value.setText(valueData.getAsJsonObject().get("text").getAsString());
        value.add(valueTextLayout);
        extractItem.setValue(value);
    }

    protected void setSY_TableKV(int offset, List<JsonObject> validJsonObjectList, ExtractItem extractItem) {
        setSY_TableKV(offset, validJsonObjectList, extractItem, null);
    }

    protected void setTableKV(JsonArray dataArray, ExtractItem extractItem) {
        if (extractItem.getKey() != null) {
            return;
        }
        JsonElement keyData = dataArray.get(0);
        JsonElement valueData = dataArray.get(1);
        KVText key = new KVText();
        TextLayout keyTextLayout = new TextLayout();
        keyTextLayout.setWidth(keyData.getAsJsonObject().get("width").getAsDouble());
        keyTextLayout.setHeight(keyData.getAsJsonObject().get("height").getAsDouble());
        keyTextLayout.setTop(keyData.getAsJsonObject().get("top").getAsDouble());
        keyTextLayout.setLeft(keyData.getAsJsonObject().get("left").getAsDouble());
        key.setText(keyData.getAsJsonObject().get("text").getAsString());
        key.add(keyTextLayout);
        keyTextLayout.setText(key.getText());
        extractItem.setKey(key);
        ///////////////////////////////////////
        KVText value = new KVText();
        TextLayout valueTextLayout = new TextLayout();
        valueTextLayout.setWidth(valueData.getAsJsonObject().get("width").getAsDouble());
        valueTextLayout.setHeight(valueData.getAsJsonObject().get("height").getAsDouble());
        valueTextLayout.setTop(valueData.getAsJsonObject().get("top").getAsDouble());
        valueTextLayout.setLeft(valueData.getAsJsonObject().get("left").getAsDouble());
        value.setText(valueData.getAsJsonObject().get("text").getAsString());
        value.add(valueTextLayout);
        extractItem.setValue(value);
        valueTextLayout.setText(value.getText());
    }


    protected TableUtil getTableUtil() {
        return TableUtil.getInstance();
    }

    protected boolean isDefaultKV(String text) {
        return regexUtil.isDefaultKV(text);
    }

    protected String findDefault_Format_Split_Char(String text) {
        return regexUtil.findDefault_Format_Split_Char(text);
    }

    protected boolean isSY_Format(String text) {
        return regexUtil.isSY_Format(text);
    }


    protected String findSY_Format_Split_Char(String text) {
        return regexUtil.findSY_Format_Split_Char(text);
    }

    protected boolean isFXTK_Format(String text) {
        return regexUtil.isFXTK_Format(text);
    }


    protected String findFXTK_Format_Split_Char(String text) {
        return regexUtil.findFXTK_Format_Split_Char(text);
    }

    protected String findFXJG_Format_Split_Char(String text) {
        return regexUtil.findFXJG_Format_Split_Char(text);
    }

    /**
     * 先这么复用吧
     * //TODO
     *
     * @param text
     * @return
     */
    protected String findFXR_Format_Split_Char(String text) {
        return regexUtil.findFXTK_Format_Split_Char(text);
    }


    protected boolean isCatalogLevel1(String text) {
        return regexUtil.isCatalogLevel1(text);
    }

    protected boolean isCatalogLevel2(String text) {
        return regexUtil.isCatalogLevel2(text);
    }

    protected boolean isChapterLevel3(String text) {
        return regexUtil.isChapterLevel3(text);
    }

    protected boolean isChapterLevel1(String text) {
        return regexUtil.isChapterLevel1(text);
    }

    protected boolean isChapterLevel2(String text) {
        return regexUtil.isChapterLevel2(text);
    }

    protected boolean isCorpName(String text) {
        return regexUtil.isCorpName(text);
    }

    protected boolean isProspectus(String text) {
        if (isEmpty(text)) {
            return false;
        }
        return regexUtil.isProspectus(text);
    }

    /**
     * 资产负债
     *
     * @param text
     * @return
     */
    protected boolean isZCFZ(String text) {
        return regexUtil.isZCFZ(text);
    }


    /**
     * 利润
     *
     * @param text
     * @return
     */
    protected boolean isLR(String text) {
        return regexUtil.isLR(text);
    }

    /**
     * 现金流量
     *
     * @param text
     * @return
     */
    protected boolean isXJLL(String text) {
        return regexUtil.isXJLL(text);
    }

    protected boolean isZCFZ_NB(String text) {
        return regexUtil.isZCFZ_NB(preProcessDate(text));
    }

    protected boolean isZCFZ_JB(String text) {
        return regexUtil.isZCFZ_JB(preProcessDate(text));
    }


    protected String getUnitType(String text) {
        return regexUtil.getUnitType(text);
    }

    /**
     * 偿债能力
     *
     * @param text
     * @return
     */
    protected boolean isCWZB_CZNL(String text) {
        return regexUtil.isCWZB_CZNL(text);
    }


    /**
     * 盈利能力
     *
     * @param text
     * @return
     */
    protected boolean isCWZB_YLNL(String text) {
        return regexUtil.isCWZB_YLNL(text);
    }

    /**
     * 运营能力
     *
     * @param text
     * @return
     */
    protected boolean isCWZB_YYNL(String text) {
        return regexUtil.isCWZB_YYNL(text);
    }

    protected boolean isYYSR(String text) {
        return regexUtil.isYYSR(text);
    }


    protected boolean isYYCB(String text) {
        return regexUtil.isYYCB(text);
    }


    protected boolean isMLR(String text) {
        return regexUtil.isMLR(text);
    }

    protected boolean isMLL(String text) {
        return regexUtil.isMLL(text);
    }

    protected boolean isDJG_XM(String text) {
        return regexUtil.isDJG_XM(text);
    }


    protected boolean isYXZW(String text) {
        return regexUtil.isYXZW(text);
    }

    protected boolean isDJG_ZW(String text) {
        return regexUtil.isDJG_ZW(text);
    }

    protected boolean isDJG(String text) {
        return regexUtil.isDJG(text);
    }

    protected boolean isZJXM(String text) {
        return regexUtil.isZJXM(text);
    }

    protected boolean isCWFX(String text) {
        return regexUtil.isCWFX(text);
    }

    protected boolean isCWFX_KM(String text) {
        return regexUtil.isCWFX_KM(text);
    }


    /**
     * 已完成工程
     *
     * @param text
     * @return
     */
    protected boolean isYWGGC(String text) {
        return regexUtil.isYWGGC(text);
    }

    protected String extractZCFZ_NB(String text) {
        return regexUtil.extractZCFZ_NB(preProcessDate(text));
    }

    private String extractZCFZ_NB_WITH_YEAR(String text) {
        return regexUtil.extractZCFZ_NB_WITH_YEAR(text);
    }

    private String extractZCFZ_JB_WITH_YEAR(String text) {
        return regexUtil.extractZCFZ_JB_WITH_YEAR(text);
    }

    protected String extractZCFZ_JB(String text) {
        return regexUtil.extractZCFZ_JB(preProcessDate(text));
    }

    protected boolean isJSNJYQ(String text) {
        return regexUtil.isJSNJYQ(text);
    }


    protected boolean isKJKMFX_ZCFZ(String text) {
        return regexUtil.isKJKMFX_ZCFZ(text);
    }


    /**
     * 受限资产表头
     *
     * @return
     */
    protected boolean isSXZC(String text) {
        return regexUtil.isSXZC(text);
    }

    /**
     * 受限资产表头
     *
     * @return
     */
    protected boolean isDWDB(String text) {
        return regexUtil.isDWDB(text);
    }


    protected boolean isMGSCW(String text) {
        return regexUtil.isMGSCW(text);
    }

    protected boolean isDWDB_JE(String text) {
        return regexUtil.isDWDB_JE(text);
    }

    protected boolean isXYPJ(String text) {
        return regexUtil.isXYPJ(text);
    }

    protected boolean isEmpty(String text) {
        return StringUtils.isEmpty(text);
    }

    protected boolean isNotEmpty(String text) {
        return StringUtils.isNotEmpty(text);
    }


    protected boolean isSXZC_JE(String text) {
        return regexUtil.isSXZC_JE(text);
    }


    protected Double getMaxLayoutValue(JsonArray array, String name) {
        Set<Double> layoutSet = new TreeSet<Double>((o1, o2) -> {
            return o2.compareTo(o1);
        });
        for (int i = 0; i < array.size(); i++) {
            JsonObject e = array.get(i).getAsJsonObject();
            layoutSet.add(e.get(name).getAsJsonPrimitive().getAsDouble());
        }
        return layoutSet.toArray(new Double[]{})[0];
    }

    /**
     * 抽取多行文本数据
     *
     * @param jsonArray
     */
    protected String extractMultiText(JsonArray jsonArray, int offset, int lineNumber) {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取文本块数据，文本内容：{}，文本行数：{}。", jsonArray.toString(), lineNumber);
        StringBuilder textStringBuilder = new StringBuilder();
        if (jsonArray.size() - offset < lineNumber) {
            lineNumber = jsonArray.size() - offset;
        }
        for (int i = 0; i < lineNumber; i++) {
            JsonArray dataArray = jsonArray.get(i + offset).getAsJsonArray();
            JsonObject data = dataArray.get(0).getAsJsonObject();
            logger.info("第：{}行数据内容为：{}。", i, dataArray);
            textStringBuilder.append(data.get("text").getAsJsonPrimitive().getAsString());
        }
        long t2 = System.currentTimeMillis();
        logger.info("抽取文本块数据完成，抽取后内容：{}，耗时：{}毫秒。", textStringBuilder.toString(), (t2 - t1));
        return textStringBuilder.toString();
    }

    /**
     * 抽取多行文本数据
     *
     * @param jsonArray
     */
    protected String extractMultiText2(JsonArray jsonArray, int offset, int lineNumber, PageModel nextPageModel) {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取文本块数据，文本内容：{}，抽取文本行数：{}。", jsonArray.toString(), lineNumber);
        StringBuilder textStringBuilder = new StringBuilder();
        if (jsonArray.size() - offset < lineNumber) {
            int diff = jsonArray.size() - offset;
            for (int i = offset; i < jsonArray.size(); i++) {
                JsonArray itemArray = jsonArray.get(i).getAsJsonArray();
                textStringBuilder.append(combineTextJsonArray(itemArray));
                logger.info("抽取文本块数据，抽取第：{}行，数据内容为：{}。", i, itemArray);
            }
            {
                int var1 = lineNumber - diff;
                JsonArray pageDataArray = nextPageModel.getJsonTextData().getAsJsonArray();
                JsonObject pageData = pageDataArray.get(0).getAsJsonObject();
                JsonArray dataArray = pageData.get("data").getAsJsonArray();
                for (int i = 0; i < var1 && i < dataArray.size(); i++) {
                    JsonArray itemArray = dataArray.get(i).getAsJsonArray();
                    textStringBuilder.append(combineTextJsonArray(itemArray));
                    logger.info("抽取文本块数据，下一页，抽取第：{}行，数据内容为：{}。", i, itemArray);
                }
            }
        } else {
            for (int i = offset; i < offset + lineNumber; i++) {
                JsonArray itemArray = jsonArray.get(i).getAsJsonArray();
                textStringBuilder.append(combineTextJsonArray(itemArray));
                logger.info("抽取文本块数据，抽取第：{}行，数据内容为：{}。", i, itemArray);
            }
        }
        long t2 = System.currentTimeMillis();
        logger.info("抽取文本块数据完成，抽取后内容：{}，耗时：{}毫秒。", textStringBuilder.toString(), (t2 - t1));
        return textStringBuilder.toString();
    }

    protected TextLayout createKVTextLayout(PageModel pageModel, JsonObject jsonObject) {
        double top = jsonObject.get("top").getAsDouble();
        if (top == 0) {
            return null;
        }
        double left = jsonObject.get("left").getAsDouble();
        double height = jsonObject.get("height").getAsDouble();
        double width = jsonObject.get("width").getAsDouble();
        TextLayout textLayout = new TextLayout(replaceSpecialChar(jsonObject.get("text").getAsString()), pageModel.getPageNumber(), top, left, height, width);
        textLayout.setPageWidth(pageModel.getWidth());
        textLayout.setPageHeight(pageModel.getHeight());
        return textLayout;
    }

    protected List<PageArea> createPageArea(TextLayout startTextLayout, TextLayout endTextLayout) {
        int startPageNumber = startTextLayout.getPageNumber();
        int endPageNumber = endTextLayout.getPageNumber();
        List<PageArea> pageAreaList = new ArrayList<>();
        double defaultLeft = 20;
        PageArea pageArea = null;
        if (startPageNumber == endPageNumber) {
            double top = startTextLayout.getTop() + startTextLayout.getHeight();
            double left = defaultLeft;
            double width = startTextLayout.getPageWidth();
            double height = endTextLayout.getTop();
            pageArea = new PageArea(startTextLayout.getPageNumber(), top, left, height, width);
            pageAreaList.add(pageArea);
        } else if (startPageNumber < endPageNumber) {
            {
                double top = startTextLayout.getTop() + startTextLayout.getHeight();
                double left = defaultLeft;
                double width = startTextLayout.getPageWidth();
                double height = startTextLayout.getPageHeight();
                pageArea = new PageArea(startTextLayout.getPageNumber(), top, left, height, width);
                pageAreaList.add(pageArea);
            }
            {
                double top = 50;
                double left = defaultLeft;
                double width = endTextLayout.getPageWidth();
                double height = endTextLayout.getTop();
                pageArea = new PageArea(endTextLayout.getPageNumber(), top, left, height, width);
                pageAreaList.add(pageArea);
            }
        }
        return pageAreaList;
    }

    protected TextLayout createKVTextLayout(PageModel pageModel, JsonArray jsonArray) {
        TextLayout textLayout = null;
        for (int i = 0; i < jsonArray.size(); i++) {
            JsonObject jsonObject = jsonArray.get(i).getAsJsonObject();
            textLayout = createKVTextLayout(pageModel, jsonObject);
            if (textLayout != null) {
                break;
            }
        }
        return textLayout;
    }

    protected PageArea createTablePageArea(PageModel pageModel, JsonArray itemArray) {
        JsonObject item = itemArray.get(0).getAsJsonObject();
        double top = item.get("top").getAsDouble();
        if (top == 0) {
            return null;
        }
        double left = 40;//item.get("left").getAsDouble();
        double height = item.get("height").getAsDouble();
        double width = item.get("width").getAsDouble();
        return new PageArea(pageModel.getPageNumber(), top, left, pageModel.getHeight(), pageModel.getWidth());
    }

    protected String replaceCRLF(String text) {
        return regexUtil.replaceCRLF(text);
    }

    protected void setExtractItemPageNumber(PageModel pageModel, ExtractItem extractItem) {
        if (extractItem.getKey() != null) {
            extractItem.getKey().setPageNumber(pageModel.getPageNumber());
        }
        if (extractItem.getValue() != null) {
            extractItem.getValue().setPageNumber(pageModel.getPageNumber());
        }
    }

    protected boolean isFXJG_SPLIT_Format(String text) {
        return regexUtil.isFXJG_SPLIT_Format(text);
    }

    protected boolean isFXTK_END(String text) {
        return regexUtil.isFXTK_END(text);
    }

    protected boolean isFXR_END(String text) {
        return regexUtil.isFXR_END(text);
    }

    protected boolean isFXR_Format(String text) {
        return regexUtil.isFXR_Format(text);
    }

    protected boolean isKJKMFX_KM(String text) {
        return regexUtil.isKJKMFX_KM(text);
    }

    protected boolean isZXQK_CATALOG(String text) {
        return regexUtil.isZXQK_CATALOG(text);
    }

    protected boolean isFXRJBQK_CATALOG(String text) {
        return regexUtil.isFXRJBQK_CATALOG(text);
    }


    protected String getNextLine(PageModel nextPageModel, JsonArray currentPageModelJsonData, int offset) {
        String text = null;
        if (offset < (currentPageModelJsonData.size() - 1)) {
            for (int i = offset; i < currentPageModelJsonData.size(); i++) {
                text = combineTextJsonArray(currentPageModelJsonData.get(i + 1).getAsJsonArray());
                if (!isEmpty(text)) {
                    break;
                }
            }
        } else {
            text = getNextPageFirstLine(nextPageModel);
        }
        return text;
    }

    protected String getNextPageFirstLine(PageModel pageModel) {
        if (pageModel == null) {
            return null;
        }
        JsonArray dataArray = getPageDataArray(pageModel);
        String text = null;
        for (int i = 0; i < dataArray.size(); i++) {
            JsonArray itemArray = dataArray.get(i).getAsJsonArray();
            text = combineTextJsonArray(itemArray);
            if (!isEmpty(text)) {
                break;
            }
//            text = dataArray.get(i).getAsJsonObject().get("text").getAsString();
//            if (isEmpty(text)) {
//                text = dataArray.get(i + 1).getAsJsonObject().get("text").getAsString();
//                if (!isEmpty(text)) {
//                    return text;
//                }
//            }
        }
        return text;
    }

    protected JsonArray getPageDataArray(PageModel pageModel) {
        if (pageModel == null) {
            return null;
        }
        JsonArray pageDataArray = pageModel.getJsonTextData().getAsJsonArray();
        JsonObject pageData = pageDataArray.get(0).getAsJsonObject();
        JsonArray dataArray = pageData.get("data").getAsJsonArray();
        return dataArray;
    }

    protected PageArea getPageArea(PageModel pageModel) {
        if (pageModel == null) {
            return null;
        }
        JsonArray pageDataArray = pageModel.getJsonTextData().getAsJsonArray();
        JsonObject pageData = pageDataArray.get(0).getAsJsonObject();
        double width = pageData.get("width").getAsDouble();
        double height = pageData.get("height").getAsDouble();
        double top = pageData.get("top").getAsDouble();
        double left = pageData.get("left").getAsDouble();
        return new PageArea(pageModel.getPageNumber(), top, left, height, width);
    }

    protected boolean isFXTK_JZBJJDAP(String text) {
        return regexUtil.isFXTK_JZBJJDAP(text);
    }

    protected boolean isFXTK_SSLTAP(String text) {
        return regexUtil.isFXTK_SSLTAP(text);
    }

    protected boolean isFXTK_JKJSAP(String text) {
        return regexUtil.isFXTK_JKJSAP(text);
    }

    protected boolean isFXTK_CATALOG(String text) {
        return regexUtil.isFXTK_CATALOG(text);
    }

    /**
     * 解析每章二级、三级标题目录
     */
    protected void parseChapterSection() {
        long t1 = System.currentTimeMillis();
        logger.info("开始分析：{}章文档结构......", getChapterModel().getChapterId());
        List<PageModel> pageModelList = getPageModelList();
        PageModel pageModel = null;
        StringBuilder stringBuilder = null;
        SectionModel currentSectionModel = null;
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            List<TableArea> tableAreaList = recognizePageTableRegion(pageModel);
            JsonArray itemArray = getPageDataArray(pageModel);
            for (int j = 0; j < itemArray.size(); j++) {
                JsonArray items = itemArray.get(j).getAsJsonArray();
                String combineLine = combineTextJsonArray(items);
                if (isEmpty(combineLine)) {
                    continue;
                }
                try {
                    if (j == (itemArray.size() - 1)) {
                        int pageNumber = getPageModelBottomPageNum(items);
                        if (pageNumber > 0) {
                            continue;
                        }
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    continue;
                }

                if (isTableNameFormat(combineLine) || isTableUnitFormat(combineLine)) {
                    logger.info("分析：{}章文档结构，文本为表格标题或者单位，分析文本：{}，跳过！！！", getChapterModel().getChapterId(), combineLine);
                    continue;
                }
                if (isInner2(items, tableAreaList)) {
                    continue;
                }
                if (isChapterLevel2(combineLine)) {
                    if (currentSectionModel != null) {
                        currentSectionModel.setContent(stringBuilder.toString());
                        currentSectionModel.setEndPage(pageModel.getPageNumber());
                    }
                    logger.info("分析：{}章文档结构，分析到二级标题，分析文本：{}。", getChapterModel().getChapterId(), combineLine);
                    SectionModel sectionModel = new SectionModel();
                    sectionModel.setStartPage(pageModel.getPageNumber());
                    sectionModel.setTitle(combineLine);
                    sectionModel.setTextLayout(createKVTextLayout(pageModel, items));
                    getChapterModel().addSectionModel(sectionModel);
                    stringBuilder = new StringBuilder();
                    currentSectionModel = sectionModel;
                    continue;
                } else if (isChapterLevel3(combineLine)) {
                    if (currentSectionModel != null) {
                        currentSectionModel.setContent(stringBuilder.toString());
                        currentSectionModel.setEndPage(pageModel.getPageNumber());
                    }
                    logger.info("分析：{}章文档结构，分析到三级标题，分析文本：{}。", getChapterModel().getChapterId(), combineLine);
                    SectionModel parentSectionModel = getChapterModel().getLastSectionModel();
                    if (parentSectionModel == null) {
                        logger.error("分析：{}章文档结构，分析到三级标题，未能发现父级标题，请确认！！！", getChapterModel().getChapterId(), combineLine);
                        continue;
                    }
                    SectionModel childSectionModel = new SectionModel();
                    parentSectionModel.addChildSectionModel(childSectionModel);
                    childSectionModel.setStartPage(pageModel.getPageNumber());
                    childSectionModel.setTitle(combineLine);
                    childSectionModel.setTextLayout(createKVTextLayout(pageModel, items));
                    stringBuilder = new StringBuilder();
                    currentSectionModel = childSectionModel;
                } else if (stringBuilder != null) {
                    stringBuilder.append(combineLine);
                }
            }
            if (i == pageModelList.size() - 1) {
                if (currentSectionModel == null || stringBuilder == null) {
                    break;
                }
                currentSectionModel.setContent(stringBuilder.toString());
                currentSectionModel.setEndPage(pageModel.getPageNumber());
            }
        }
        long t2 = System.currentTimeMillis();
        logger.info("分析：{}章文档结构完成，耗时：{}毫秒。", getChapterModel().getChapterTitle(), (t2 - t1));
    }


    protected boolean isInner3(JsonArray itemArray, PageModel pageModel) {
        List<TableArea> tableAreaList = recognizePageTableRegion(pageModel);
        if (CollectionUtils.isEmpty(tableAreaList)) {
            return false;
        }
        boolean isInner = false;
        for (int i = 0; i < itemArray.size(); i++) {
            JsonObject jsonObject = itemArray.get(i).getAsJsonObject();
            double height = jsonObject.get("height").getAsDouble();
            double top = jsonObject.get("top").getAsDouble();
            double left = jsonObject.get("left").getAsDouble();
            if (top == 0 && left == 0) {
                continue;
            }
            for (int j = 0; j < tableAreaList.size(); j++) {
                TableArea tableArea = tableAreaList.get(j);
                if (top > tableArea.getTop() && (top + height) < (tableArea.getTop() + tableArea.getHeight())) {
                    isInner = true;
                    break;
                }
            }
        }
        return isInner;
    }


    protected boolean isInner2(JsonArray itemArray, List<TableArea> tableAreaList) {
        if (CollectionUtils.isEmpty(tableAreaList)) {
            return false;
        }
        boolean isInner = false;
        for (int i = 0; i < itemArray.size(); i++) {
            JsonObject jsonObject = itemArray.get(i).getAsJsonObject();
            double height = jsonObject.get("height").getAsDouble();
            double top = jsonObject.get("top").getAsDouble();
            double left = jsonObject.get("left").getAsDouble();
            if (top == 0 && left == 0) {
                continue;
            }
            for (int j = 0; j < tableAreaList.size(); j++) {
                TableArea tableArea = tableAreaList.get(j);
                if (top > tableArea.getTop() && (top + height) < (tableArea.getTop() + tableArea.getHeight())) {
                    isInner = true;
                    break;
                }
            }
        }
        return isInner;
    }

    protected String replaceSpaces(String text) {
        return regexUtil.replaceSpaces(text);
    }


    protected List<TableArea> recognizePageTableRegion(PageModel pageModel) {
        logger.info("抽取{}章节业务模型数据，分析{}页是否存在表格.......", getChapterModel().getChapterId(), pageModel.getPageNumber());
//        PageArea pageArea = new PageArea(pageModel.getPageNumber(), 60, 20, pageModel.getHeight(), pageModel.getWidth());
        List<TableArea> tableAreaList = new ArrayList<>();
        try {
            List<String> pageTableDataList = pageModel.getTableDataList();//extractPdfByTable(new String[]{getDocumentModel().getPdfFilePath(), "-l", "-p", String.valueOf(pageModel.getPageNumber()), "-a", pageArea.getLayout(), "-f", "JSON"});
            if (CollectionUtils.isEmpty(pageTableDataList)) {
                return null;
            }
            for (int i = 0; i < pageTableDataList.size(); i++) {
                String tableJsonData = pageTableDataList.get(i);
                JsonArray tableDataArray = str2Json(tableJsonData).getAsJsonArray();
                JsonObject tableData = tableDataArray.get(0).getAsJsonObject();
                double top = tableData.get("top").getAsDouble();
                double left = tableData.get("left").getAsDouble();
                double width = tableData.get("width").getAsDouble();
                double height = tableData.get("height").getAsDouble();
                TableArea tableArea = new TableArea(pageModel.getPageNumber(), top, left, width, height);
                tableAreaList.add(tableArea);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("抽取{}章节业务模型数据，分析{}页是否存在表格完成，表格数量：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), tableAreaList.size());
        return tableAreaList;
    }

    protected int getPageModelBottomPageNum(JsonArray items) {
        String text = combineTextJsonArray(items);
        if (org.apache.commons.lang3.StringUtils.isEmpty(text)) {
            return 0;
        }
        text = text.replaceAll("\\s{0,}", "");
        String regex = "\\d{1,3}";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        if (matcher.matches()) {
            return Integer.parseInt(text);
        } else {
            return 0;
        }
    }

    protected boolean isBottomPageNumber(JsonArray items) {
        if (getPageModelBottomPageNum(items) >= 0) {
            return true;
        } else {
            return false;
        }
    }

    protected void setTableUnitType(ExtractBizModel extractBizModel, String text) {
        extractBizModel.setUnitType(getUnitType(text));
    }

    protected void setTableNameTextLayout(PageModel pageModel, ExtractBizModel extractBizModel, JsonArray itemArray) {
        extractBizModel.setTableNameTextLayout(createKVTextLayout(pageModel, itemArray));
    }


    protected void clearEmptyCell(JsonArray dataArray, int maxColumn, int offset) {
        for (int i = offset; i < dataArray.size(); i++) {
            JsonArray itemArray = dataArray.get(i).getAsJsonArray();
            List<JsonElement> emptyElementList = new ArrayList<>();
            for (int j = 0; j < itemArray.size(); j++) {
                if (maxColumn == itemArray.size()) {
                    continue;
                } else if (maxColumn < itemArray.size()) {
                    JsonObject jsonObject = itemArray.get(j).getAsJsonObject();
                    String text = jsonObject.get("text").getAsString();
                    if (isEmpty(text)) {
                        emptyElementList.add(jsonObject);
                    }
                }
            }
            if (!emptyElementList.isEmpty()) {
                emptyElementList.forEach(e -> {
                    itemArray.remove(e);
                });
            }
        }
    }

    protected boolean isAmtUnit(String text) {
        return regexUtil.isAmtUnit(text);
    }


    protected boolean isHJFormat(String text) {
        return regexUtil.isHJFormat(text);
    }

    protected boolean isZJXM_UNIT(String text) {
        return regexUtil.isZJXM_UNIT(text);
    }

    protected boolean isYWCGC_UNIT(String text) {
        return isZJXM_UNIT(text);
    }

    protected boolean isTableUnitFormat(String text) {
        return regexUtil.isTableUnitFormat(text);
    }

    protected boolean isTableNameFormat(String text) {
        return regexUtil.isTableNameFormat(text);
    }

    protected String preProcessDate(String text) {
        return regexUtil.preProcessDate(text);
    }

    protected TextLayout cloneTextLayout(TextLayout textLayout) {
        TextLayout newTextLayout = new TextLayout();
        newTextLayout.setTop(textLayout.getTop());
        newTextLayout.setLeft(textLayout.getLeft());
        newTextLayout.setPageNumber(textLayout.getPageNumber());
        return newTextLayout;
    }

    protected boolean isStatement(String text) {
        List<String> statementList = regexUtil.getStatementList();
        for (String statement : statementList) {
            double similarity = getSimilarAnalyser().similarity(text, statement);
            if (similarity > 0.8) {
                return true;
            }
        }
        return false;
    }

    protected String joinSynonyms(String[] synonyms) {
        return regexUtil.joinSynonyms(synonyms);
    }

    protected JsonElement str2Json(String jsonString) {
        return gsonUtil.parse(jsonString);
    }

}

